package com.xuanwei.web.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.xuanwei.core.annos.Single;
import com.xuanwei.core.enums.OrderStatus;
import com.xuanwei.core.enums.PayHandleType;
import com.xuanwei.core.exception.XwException;
import com.xuanwei.core.response.ResultVO;
import com.xuanwei.core.service.IXwOrderPayLogService;
import com.xuanwei.core.service.IXwOrderService;
import com.xuanwei.dao.entity.XwOrder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author jiangyong
 * @Description TODO
 * @Date 2019/7/12 14:04
 **/
@RestController
@RequestMapping("wx/pay")
@Validated
public class PayController extends BasicController {

    private IXwOrderService orderService;

    private WxPayService payService;

    private IXwOrderPayLogService payLogService;

    public PayController(IXwOrderService orderService, WxPayService payService,
                         IXwOrderPayLogService payLogService) {
        this.orderService = orderService;
        this.payService = payService;
        this.payLogService = payLogService;
    }

    /**
     * 购物车挑战支付
     *
     * @return 响应
     */
    @Single
    @RequestMapping(value = "cartToPay", method = RequestMethod.GET)
    public ResultVO cartToPay(@NotBlank(message = "参数错误") String cartId,
                              @Min(value = 1, message = "参数错误") Integer addressId,
                              @Min(value = 1, message = "参数错误") Integer couponId,
                              String remark) throws UnknownHostException {
        List<Integer> ids = Arrays.stream(cartId.split("-")).map(Integer::parseInt).collect(Collectors.toList());
        XwOrder order = orderService.generateOrder(ids, addressId, remark, couponId, getUserId());
        if (order.getActualAmount().intValue() == 0) {
            orderService.orderSuccess(order.getOrderNo());
            return ResultVO.successResult("支付成功");
        }
        return pay(order);
    }

    /**
     * 直接支付
     *
     * @return 响应
     */
    @Single
    @RequestMapping(value = "toPay", method = RequestMethod.GET)
    public ResultVO toPay(@Min(value = 1, message = "参数错误") Integer skuId,
                          @Min(value = 1, message = "参数错误") Integer count,
                          @Min(value = 1, message = "参数错误") Integer addressId,
                          @Min(value = 1, message = "参数错误") Integer couponId,
                          String remark) throws UnknownHostException {

        XwOrder order = orderService.generateOrder(skuId, count, addressId, remark, couponId, getUserId());
        if (order.getActualAmount().intValue() == 0) {
            orderService.orderSuccess(order.getOrderNo());
            return ResultVO.successResult("支付成功");
        }
        return pay(order);
    }

    /**
     * 未支付的支付
     * @param orderId 订单ID
     * @return 响应
     * @throws UnknownHostException
     */
    @Single
    @RequestMapping(value = "goOn", method = RequestMethod.GET)
    public ResultVO toPay(Integer orderId) throws UnknownHostException {
        XwOrder order = orderService.getOne(new QueryWrapper<XwOrder>()
                .eq("id", orderId)
                .in("`status`", OrderStatus.PAY_NO.getCode(), OrderStatus.NO.getCode()));
        if (order == null) {
            return ResultVO.failResult("该订单不存在");
        }
        if (order.getActualAmount().intValue() == 0) {
            orderService.orderSuccess(order.getOrderNo());
            return ResultVO.successResult("支付成功");
        }
        return pay(order);
    }

    /**
     * 微信支付异步通知
     */
    @RequestMapping("payNotify")
    public String payNotify(@RequestBody String xmlData) {
        try {
            WxPayOrderNotifyResult result = payService.parseOrderNotifyResult(xmlData);
            if ("SUCCESS".equals(result.getResultCode())) {
                //成功
                orderService.orderSuccess(result.getOutTradeNo());

                //插入日志
                payLogService.insert(result.getOutTradeNo(), "SUCCESS", result, PayHandleType.QUERY);
                return WxPayNotifyResponse.success("success");
            }
            return WxPayNotifyResponse.fail("fail");
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    /**
     * 支付
     *
     * @param order 订单数据
     * @return 响应
     */
    private ResultVO pay(XwOrder order) throws UnknownHostException {
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setBody(order.getPayBody());
        request.setOutTradeNo(order.getOrderNo());
        String miniAppOpenid = getUser().getMiniAppOpenid();
        if (StringUtils.isBlank(miniAppOpenid)) {
            throw new XwException("未授权");
        }
        request.setOpenid(miniAppOpenid);
        request.setTotalFee(order.getActualAmount().multiply(new BigDecimal(100)).intValue());
        request.setSpbillCreateIp(InetAddress.getLocalHost().getHostAddress());
        try {
            WxPayUnifiedOrderResult result = payService.unifiedOrder(request);
            //构建支付所需参数
            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
            String nonceStr = String.valueOf(System.currentTimeMillis());
            String signType = WxPayConstants.SignType.MD5;
            String appid = result.getAppid();
            WxPayMpOrderResult payResult = WxPayMpOrderResult.builder()
                    .appId(appid)
                    .timeStamp(timestamp)
                    .nonceStr(nonceStr)
                    .packageValue("prepay_id=" + result.getPrepayId())
                    .signType(signType)
                    .build();
            payResult.setPaySign(SignUtils.createSign(payResult, signType, payService.getConfig().getMchKey(), null));

            //插入日志(没有将生成订单放在一个事务)
            payLogService.insert(order.getOrderNo(), result, PayHandleType.PAY);
            return ResultVO.successResult(payResult);
        } catch (WxPayException e) {
            e.printStackTrace();
            return ResultVO.failResult("系统异常");
        }
    }
}
